#include "XService.h"
#include "XServiceHandle.h"
#include "thread_pool/XThreadPool.h"
#include <event2/bufferevent.h>
#include <event2/listener.h>
#include "XTools.h"
#include <sstream>
static void SListenCB(struct evconnlistener *listener,
                      evutil_socket_t cfd,
                      struct sockaddr *addr, int socklen, void *arg)
{
    XCOM_LOG_DEBUG("SListenCB");
    XService *service = (XService *)arg;
    service->ListenCB(cfd, addr, socklen);
}

XService::XService()
{
    this->thread_listen_pool_ = XThreadPoolFactory::Create();
    this->thread_client_pool_ = XThreadPoolFactory::Create();
}

XService::~XService()
{
    delete this->thread_listen_pool_;
    this->thread_listen_pool_ = nullptr;
    delete this->thread_client_pool_;
    this->thread_client_pool_ = nullptr;
}

bool XService::Start()
{
    this->thread_listen_pool_->init(1);
    this->thread_client_pool_->init(thread_count_);
    this->thread_listen_pool_->dispatch(this);
    return true;
}

bool XService::Init()
{
    if (server_port_ == 0)
    {
        XCOM_LOG_ERROR("server_port_ is 0");
        return false;
    }
    if (base() == nullptr)
    {
        XCOM_LOG_ERROR("base is nullptr");
        return false;
    }
    sockaddr_in addr = {0};
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = INADDR_ANY;
    addr.sin_port = htons(server_port_);
    evconnlistener *listener = evconnlistener_new_bind(
        base(),
        SListenCB,
        this,
        LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE,
        10,
        (sockaddr *)&addr,
        sizeof(addr)
    );
    if(listener == nullptr)
    {
        XCOM_LOG_ERROR("listen port: "<<server_port_<<" failed!");
        return false;
    }
    XCOM_LOG_DEBUG("listen port: "<<server_port_<<" success!");
    return true;
}

void XService::ListenCB(evutil_socket_t cfd, struct sockaddr *addr, int socklen)
{
    XCOM_LOG_DEBUG("ListenCB");
    // 
    XServiceHandle *handle = CreateServiceHandle();
    if (handle == nullptr)
    {
        XCOM_LOG_ERROR("CreateServiceHandle failed!");
        return;
    }
    handle->setSSLCtx(sslCtx());
    handle->setSock(cfd);
    auto caddr = (sockaddr_in *)addr;
    evutil_inet_ntop(AF_INET, &caddr->sin_addr.s_addr, handle->client_ip(), XServiceHandle::CLIENT_IP_LEN);
    handle->set_client_port(ntohs(caddr->sin_port));
    XCOM_LOG_INFO("client ip: "<<handle->client_ip()<<" port: "<<handle->client_port()<<" connect!");
    this->thread_client_pool_->dispatch(handle);
}
